package framework.util.fileUpload.service.impl;

import com.esotericsoftware.reflectasm.MethodAccess;
import framework.common.Common;
import framework.util.fileUpload.bo.SysFile;
import framework.util.fileUpload.bo.SysFileModule;
import framework.util.fileUpload.dao.ISysFileDao;
import framework.util.fileUpload.service.SysFileService;
import framework.util._BeanUtil;
import framework.util.jdkExt._FileUtil;
import framework.util._PropertyUtil;
import framework.util.fileUpload.vo._FileUploadJavaBean;
import framework.util.jdkExt._TimeUtil;
import framework.util.layui._LayuiUtil;
import framework.util.queryFilter.service.impl.IBaseServiceImpl;
import javax.annotation.Resource;

import framework.util.queryFilter.service.impl.QueryFilter;
import framework.util.queryFilter.vo.Where;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Properties;
import java.util.function.Supplier;

@Service("SysFileService")
public class SysFileServiceImpl extends IBaseServiceImpl<SysFile, Integer> implements SysFileService {

    @Resource
    private ISysFileDao dao;

    private static Properties properties = null;
    static {
        try {
            properties = _PropertyUtil.loadInClassPath("properties/framework.properties");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //临时文件夹
    /** 临时文件夹 **/
    private static final String uploadTmpFileRootDir = properties.getProperty("server.uploadTmpFileRootDir").replaceAll("//", File.separator);
    /** 临时文件夹 **/
    private static final String readTmpFileRootDir = properties.getProperty("server.readTmpFileRootDir");
    //真正存放文件的文件夹
    /** 真正存放文件的文件夹 **/
    private static final String uploadFileRootDir = properties.getProperty("server.uploadFileRootDir").replaceAll("//", File.separator);
    /** 真正存放文件的文件夹 **/
    private static final String readFileRootDir = properties.getProperty("server.readFileRootDir");


    @Override
    public synchronized SysFile upload(MultipartFile multipartFile, SysFileModule sysFileModule, String uuid, Supplier<String> customFoldSupplier) throws Exception {
        //如果为单文件上传，则要覆盖之前的文件(即删除)
        if(Common.IS_NO == sysFileModule.getIsMultiple()){
            QueryFilter filter = new QueryFilter(_LayuiUtil.FIRST_PAGE, Integer.MAX_VALUE);
            filter.where(SysFile.UUID, Where.eq, uuid);
            filter.where(SysFile.MODULE_LID, Where.eq, sysFileModule.getLid());
            List<SysFile> oldFileList = this.getAll(filter);
            for (SysFile sysFile : oldFileList) {
                this.deleteFile(sysFile);
            }
        }

        //自定义文件夹
        String customFold = customFoldSupplier.get();
        customFold = StringUtils.isNoneBlank(customFold) ? File.separator + customFold : "";

        //创建文件夹
        String dirPrefix = properties.getProperty("server.uploadTmpFileRootDir").replaceAll("//", File.separator);
        String dirSuffix =  sysFileModule.getTableName() + File.separator + sysFileModule.getModuleEname() + customFold;
        String fileDirtory = dirPrefix + File.separator + dirSuffix;
        _FileUtil.createDir(new File(fileDirtory));

        //获得原始文件名
        String fileName = multipartFile.getOriginalFilename();
        //构建文件名：给文件名添加时间戳，防止文件名重复
        fileName = System.currentTimeMillis() + "_" + fileName;
        //用MultipartFile对象生成file文件（transferTo使用的是绝对路径）
        multipartFile.transferTo(new File(fileDirtory + File.separator + fileName));
        //但是读是通过Tomcat的虚拟路径去读的，所以要转换成虚拟路径
        String url = properties.getProperty("server.readTmpFileRootDir") + File.separator + dirSuffix + File.separator + fileName;

        SysFile sysFile = new SysFile();
        sysFile.setModuleLid(sysFileModule.getLid());
        sysFile.setUuid(uuid);
        sysFile.setName(multipartFile.getOriginalFilename());
        sysFile.setB(new Long(multipartFile.getSize()).doubleValue());
        sysFile.setKb(_FileUtil.byteTransformKb(sysFile.getB()));
        sysFile.setMb(_FileUtil.byteTransformMb(sysFile.getB()));
        sysFile.setUrl(url);
        sysFile.setOperatorTime(_TimeUtil.now("yyyy-MM-dd HH:mm:ss"));
        return sysFile;
    }

    @Override
    public synchronized SysFile upload(MultipartFile multipartFile, SysFileModule sysFileModule, String uuid) throws Exception {
        return upload(multipartFile, sysFileModule, uuid, () -> "");
    }

    @Override
    public void deleteFiles(String... sysFileLids) {
        for (String sysFileLid : sysFileLids) {
            //删除文件
            SysFile sysFile = this.get(Integer.valueOf(sysFileLid));
            this.deleteFile(sysFile);
        }
    }

    /**
     * 删除单个文件
     * @param sysFile 待删除的文件
     */
    private void deleteFile(SysFile sysFile) {
        if(null == sysFile){
            return;
        }
        ///第一步： 删除文件
        String url = sysFile.getUrl();
        if(url.startsWith(readTmpFileRootDir) ){
            url = url.replace(readTmpFileRootDir, uploadTmpFileRootDir);
        }else if(url.startsWith(readFileRootDir) ){
            url = url.replace(readFileRootDir, uploadFileRootDir);
        }
        _FileUtil.deleteFile(url);

        ///第二步：删除文件附件记录
        //删除文件附件表记录
        this.remove(sysFile);
    }

    @Override
    public List<SysFile> getFiles(Object bo, String moduleEname) {
        return getFiles(bo, moduleEname, new QueryFilter(_LayuiUtil.FIRST_PAGE, Integer.MAX_VALUE));
    }

    @Override
    public List<SysFile> getFiles(Object bo, String moduleEname, QueryFilter fileFilter) {
        String simpleName = bo.getClass().getSimpleName();
        String tableName = _BeanUtil.transformUpperCase2_(simpleName);

        ///第一步：查找文件
        MethodAccess methodAccess = MethodAccess.get(QueryFilter.class);
        methodAccess.invoke(fileFilter, "setTableName", tableName);
        fileFilter.getWhereList().forEach(item -> {
            try {
                item.generatorSql(persistType);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        });

        fileFilter.getWhereList().forEach(where -> where.getGeneratorSql());
        List<SysFile> fileList = dao.getFiles(bo, moduleEname, fileFilter);

        ///第二步：如果bo继承了_FileUploadJavaBean，则直接将找到的文件放在fileMap
        if(bo instanceof _FileUploadJavaBean){
            _FileUploadJavaBean fileUploadJavaBean = (_FileUploadJavaBean) bo;
            fileUploadJavaBean.getFileMap().put(moduleEname, fileList);
        }
        return fileList;
    }

    @Override
    public void encodeURIComponent(SysFile sysFile) throws UnsupportedEncodingException {
        String url = sysFile.getUrl();
        if(StringUtils.isBlank(url)){
            return;
        }
        String prefix = url.substring(0, url.lastIndexOf(File.separator) + 1)
                ,suffix = url.substring(url.lastIndexOf(File.separator) + 1);
        sysFile.setUrl(prefix + URLEncoder.encode(suffix, "UTF-8"));
    }

}

